#include <iostream>
#include <boost/filesystem/path.hpp>
#include <string>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <boost/regex.hpp>
#include "get_arg.h"
using std::string;
using std::ofstream;
using std::ifstream;
using std::fstream;
using std::cerr;
using std::cout;


// my functions
#include <print_error.h>
#include <program_options_helper.h>

using namespace program_options_helper;
namespace po = boost::program_options_lg;



namespace {
enum eREQUIRE {OPTIONAL, NOT_OPTIONAL};
template <typename FSTRM> void open_arg_file(string& file_path, FSTRM& strm,
												std::ostream& VERBOSE,
												eREQUIRE req = OPTIONAL)
{
	if (!file_path.length() && req == OPTIONAL)
		return;

	// make sure the file_name is valid
	if (file_path.length())
		strm.open(file_path.c_str());
	if (!file_path.length() || !strm.good())
		throw std::runtime_error("Could not open the file (" + file_path + ").");
	file_path = boost::filesystem::path(file_path).leaf();
}
}








//_______________________________________________________________________________________

//		process_command_line_options


//_______________________________________________________________________________________
bool process_command_line_options(int argc, char* argv[], t_program_args& args)
{
	//
	// mandatory arguments
	//
	po::options_description mandatory_args("Mandatory Arguments");
	mandatory_args.add_options()
	("peptide_sequences,p", 	po::value<string>(&args.prot__in)->set_name("FILE"),
									"Input peptides in FASTA format. ")
	("cdna_sequences,c", 		po::value<string>(&args.cdna__in)->set_name("FILE"),
									"Input cDNA sequences in FASTA format. ")
	("peptide_output,P", 		po::value<string>(&args.prot_out)->set_name("FILE"),
									"Output mapped peptides in FASTA format. ")
	("cdna_output,C", 			po::value<string>(&args.cdna_out)->set_name("FILE"),
									"Output mapped cDNA sequences in FASTA format. ");



	//
	// optional arguments
	//
	args.use_X_for_aa_mismatches = '\x0';
	args.optional_args.add_options()
	("table_of_mapped_cdna,t", 	po::value<string>(&args.cdna_tout)->set_name("FILE"),
									"Output mapped cDNA sequences / hash of (prot) / "
									"accession codes / hash of (cdna) in a table. ")
	("intron_output,i", 		po::value<string>(&args.intron_out)->set_name("FILE"),
									"Output unmapped cDNA.")
	("regex,r", 				po::value<string>(&args.regex_str)->set_name("REGEX")
									->default_value("(\\S+)"),
									"Regular expression for extracting accession codes.\1"
									"Defaults to first non-whitespace characters on the "
									"accession line.")
	("x_for_aa_mismatches,x", 	po::value<char>(&args.use_X_for_aa_mismatches)->set_name("LETTER"),
									"Specifies LETTER to be substituted instead of deleting "
									"the residue, when no matching codon is found for "
									"a residue. The corresponding codon will always be 'NNN'.")
	("matching,m", 				po::value<unsigned>(&args.consecutive_matching_aa)
									->default_value(6)->set_name("NUMBER"),
									"Minimum continuous stretch of matching amino acids for "
									"a match."
									"Reducing this number often produces much worse alignments.")
	("missing_identifiers,M", 	po::value<string>(&args.missing_identifiers)->set_name("FILE"),
									"List cDNA sequences without corresponding peptides.");

	args.add_std_options();
	args.use_results_summary();
	po::options_description all_args("");
	all_args.add(mandatory_args).add(args.optional_args);


	// parse command line
	po::variables_map vm;
	po::store(po::command_line_parser(argc, argv).options(all_args).run(), vm);
	po::notify(vm);

	if (vm.count("version"))
	{
		print_version(	cerr, *argv, "1.6\n"
						"\tHistory: \n\n"
						"\tv 1.0\1"
						"Initial version\n"
						"12-02-2003\1"
						"\tv 1.1\1"
						"20-10-2004\1"
						"Bug Fix. Now rejects all stop codons, even those represented by 'X'\n"
						"\tv 1.2\1"
						"29-11-2004\1"
						"Improved programme description (this message).\n"
						"\tv 1.3\1"
						"18-05-2005\1"
						"Changed programme parameter names. Sorry everyone. "
						"The new names are a great improvement. Honest.\n"
						"\tv 1.4\1"
						"19-05-2005\1"
						"Fixed bugs in initial alignment.\1"
						"Now produces intron loci.\n"
						"\tv 1.5\1"
						"08-02-2006\1"
						"'X' now matches stop codons (tri-frame translates to '*'\1"
						"This is because exonerate gives stops as X.\1"
						"Changes in both map_cdna_to_prot() and find_consecutive_aa_matches()"
						"To handle Ensembl stops, asterisks are converted to X as well.\1"
						"This should be removed when full backfilling matches is "
						"implemented.\1"
						"Better instrumentation for debug builds.\1"
						"Summary of errors in error file as well as verbose.\n"
						"\tv 1.6\1"
						"15-03-2006\1"
						"Added MD4 hash of cdna sequences to table output\n"
						"\tv 1.7\1"
						"10-07-2006\1"
						"Output missing identifiers separately.\n"
						"\tv 1.8\1"
						"04-10-2006\1"
						"Bug fix: Stops '*' were turned into X but the codon was flagged as "
						"missing rather than NNN. Worked only when x_for_aa_mismatches was "
						"specified. Now works correctly.\n"
			);
		return false;
	}
	if (vm.count("help"))
	{
		string exe_description =
				"Maps cDNA and peptides sequences with common "
				"IDs to each other.\n"
				"The resulting cDNA and peptide output will be codon-by-codon, "
				"residue-by-residue equivalent.\n"
				"Sequence IDs are extracted using a regular expression.\n"
				"Introns are output in a tab delimited format with the first column being "
				"the start position. The second column is the intron length in bases."
				"If the peptide sequences is aligned (with hyphens), the "
				"alignment will be preserved (with hyphens) in the cDNA as well.\n"
				"N.B. Other non-coding letters (i.e. except hyphens) are discarded.\n"
				"All stop codons will be removed. Handle stops yourself!!!\n"
				;

		print_usage(cerr, string(*argv), 	"[OPTIONS]\n"
											"--peptide_sequences FILE\n"
											"--cdna_sequences FILE\n"
											"--peptide_output FILE\n"
											"--cdna_output FILE\n",
							all_args, exe_description, 80);
		return false;
	}
	check_required_options(vm, mandatory_args);



	// make sure each file is valid
	open_arg_file(args.prot__in, args.f_prot__in, 	args.VERBOSE(), NOT_OPTIONAL		);  
	open_arg_file(args.cdna__in, args.f_cdna__in, 	args.VERBOSE(), NOT_OPTIONAL		);  
	open_arg_file(args.prot_out, args.f_prot_out, 	args.VERBOSE(), NOT_OPTIONAL		);  
	open_arg_file(args.cdna_tout, 			args.f_cdna_tout, 			args.VERBOSE()	);  
	open_arg_file(args.cdna_out, 			args.f_cdna_out, 			args.VERBOSE()	);  
	open_arg_file(args.intron_out, 			args.f_intron_out, 			args.VERBOSE()	);  
	open_arg_file(args.missing_identifiers, args.f_missing_identifiers, args.VERBOSE()	);  
	


	try
	{
		boost::regex acc_code_regex(args.regex_str);
	}
	catch (...)
	{
		throw std::runtime_error("This regular expression is not valid: (" + args.regex_str + ").");
	}

	args.open_err_log();
	return true;
}




